package hos.retrofit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import hos.retrofit.anotation.Byte;
import hos.retrofit.anotation.DownloadUrl;
import hos.retrofit.anotation.ExceptionInterceptor;
import hos.retrofit.anotation.File;
import hos.retrofit.anotation.Header;
import hos.retrofit.anotation.HeaderMap;
import hos.retrofit.anotation.Json;
import hos.retrofit.anotation.Param;
import hos.retrofit.anotation.ParamMap;
import hos.retrofit.anotation.Query;
import hos.retrofit.anotation.QueryMap;
import hos.retrofit.anotation.RequestInterceptor;
import hos.retrofit.anotation.ResponseInterceptor;
import hos.retrofit.anotation.SoapHeader;
import hos.retrofit.anotation.SoapHeaderMap;
import hos.retrofit.anotation.Tag;
import hos.retrofit.anotation.Txt;
import hos.retrofit.anotation.Url;

/**
 * <p>Title: RetrofitParameter </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2024-04-13 12:49
 */
public class RetrofitRequest {


    private String baseUrl;
    private String baseUrlEnd;
    private RetrofitInterceptor.RequestInterceptor requestInterceptor;
    private RetrofitInterceptor.ResponseInterceptor responseInterceptor;
    private RetrofitInterceptor.ExceptionInterceptor exceptionInterceptor;
    private String url;
    private Object body;
    private Object tag;
    private Map<String, Object> bodyParam;
    private List<RetrofitFile> fileList;
    private final int soapVersion;
    private final boolean soapDotNet;
    private String soapNameSpace;
    private final String httpMethod;
    private final Type genericReturnType;
    private final Map<String, String> headers;
    private Map<String, String> soapHeaders;
    private final boolean allowUnsafeNonAsciiValues;
    private final String contentType;
    private Map<String, Object> urlParam;
    private final boolean hasBody;
    private final boolean isFormEncoded;
    private final boolean isMultipart;

    private RetrofitRequest(Retrofit retrofit, RetrofitRequestFactory requestFactory, Object[] args) {
        this.baseUrl = requestFactory.getBaseUrl();
        if (this.baseUrl == null || this.baseUrl.length() == 0) {
            this.baseUrl = retrofit.getBaseUrl();
        }
        this.baseUrlEnd = requestFactory.getBaseUrlEnd();
        if (this.baseUrlEnd == null || this.baseUrlEnd.length() == 0) {
            this.baseUrlEnd = retrofit.getBaseUrlEnd();
        }
        this.soapNameSpace = requestFactory.getSoapNameSpace();
        if (this.soapNameSpace == null || this.soapNameSpace.length() == 0) {
            this.soapNameSpace = retrofit.getNameSpace();
        }
        headers = new LinkedHashMap<>();
        Map<String, String> headerCommon = retrofit.getHeader();
        if (headerCommon != null) {
            this.headers.putAll(headerCommon);
        }
        Map<String, String> headers = requestFactory.getHeaders();
        if (headers != null) {
            this.headers.putAll(headers);
        }
        this.hasBody = requestFactory.isHasBody();
        Map<String, Object> parameters = retrofit.getParameters();
        if (hasBody) {
            if (bodyParam == null) {
                bodyParam = new LinkedHashMap<>();
            }
            if (parameters != null) {
                bodyParam.putAll(parameters);
            }
        } else {
            if (urlParam == null) {
                urlParam = new LinkedHashMap<>();
            }
            if (parameters != null) {
                urlParam.putAll(parameters);
            }
            Map<String, Object> factoryUrlParam = requestFactory.getUrlParam();
            if (factoryUrlParam != null) {
                urlParam.putAll(factoryUrlParam);
            }
        }
        requestInterceptor = retrofit.getRequestInterceptor();
        responseInterceptor = retrofit.getResponseInterceptor();
        exceptionInterceptor = retrofit.getExceptionInterceptor();
        this.soapVersion = requestFactory.getSoapVersion();
        this.url = requestFactory.getUrl();
        this.httpMethod = requestFactory.getHttpMethod();
        this.genericReturnType = requestFactory.getGenericReturnType();
        this.soapHeaders = requestFactory.getSoapHeaders();
        this.allowUnsafeNonAsciiValues = requestFactory.isAllowUnsafeNonAsciiValues();
        this.contentType = requestFactory.getContentType();
        this.isFormEncoded = requestFactory.isFormEncoded();
        this.isMultipart = requestFactory.isMultipart();
        this.soapDotNet = requestFactory.isSoapDotNet();
        List<RetrofitParamAnnotation> methodParam = requestFactory.getMethodParam();
        for (RetrofitParamAnnotation paramAnnotation : methodParam) {
            Annotation annotation = paramAnnotation.getAnnotation();
            Type type = paramAnnotation.getType();
            String key = paramAnnotation.getKey();
            Object param = args[paramAnnotation.getIndex()];
            if (annotation instanceof RequestInterceptor) {
                requestInterceptor = (RetrofitInterceptor.RequestInterceptor) param;
            }
            if (annotation instanceof ResponseInterceptor) {
                responseInterceptor = (RetrofitInterceptor.ResponseInterceptor) param;
            }
            if (annotation instanceof ExceptionInterceptor) {
                exceptionInterceptor = (RetrofitInterceptor.ExceptionInterceptor) param;
            }
            if (annotation instanceof Url) {
                url = param.toString();
            }
            if (annotation instanceof DownloadUrl) {
                url = param.toString();
            }
            if (annotation instanceof Txt) {
                body = param;
            }
            if (annotation instanceof Json) {
                body = param;
            }
            if (annotation instanceof Byte) {
                body = param;
            }
            if (annotation instanceof Tag) {
                this.tag = param;
            }
            if (annotation instanceof SoapHeaderMap) {
                if (param != null) {
                    if (soapHeaders == null) {
                        soapHeaders = new LinkedHashMap<>();
                    }
                    if (type instanceof Map) {
                        //noinspection unchecked
                        soapHeaders.putAll((Map<String, String>) param);
                    }
                }
            }
            if (annotation instanceof SoapHeader) {
                if (soapHeaders == null) {
                    soapHeaders = new LinkedHashMap<>();
                }
                soapHeaders.put(key, String.valueOf(param));
            }
            if (annotation instanceof QueryMap) {
                if (param != null) {
                    //noinspection unchecked
                    urlParam.putAll((Map<String, Object>) param);
                }
            }
            if (annotation instanceof Query) {
                if (param != null) {
                    urlParam.put(key, String.valueOf(param));
                }
            }
            if (annotation instanceof ParamMap) {
                if (param != null) {
                    if (bodyParam == null) {
                        bodyParam = new LinkedHashMap<>();
                    }
                    //noinspection unchecked
                    bodyParam.putAll((Map<String, Object>) param);
                }
            }
            if (annotation instanceof Param) {
                if (bodyParam == null) {
                    bodyParam = new LinkedHashMap<>();
                }
                bodyParam.put(key, param);
            }

            if (annotation instanceof HeaderMap) {
                if (param != null) {
                    //noinspection unchecked
                    this.headers.putAll((Map<String, String>) param);
                }
            }
            if (annotation instanceof Header) {
                if (param != null) {
                    this.headers.put(key, String.valueOf(param));
                }
            }
            if (annotation instanceof File) {
                if (fileList == null) {
                    fileList = new LinkedList<>();
                }
                if (param != null) {
                    fileList.add(new RetrofitFile(key, String.valueOf(param)));
                }
            }

        }
    }


    public String getBaseUrl() {
        return baseUrl;
    }

    public String getBaseUrlEnd() {
        return baseUrlEnd;
    }

    public String getUseUrl() {
        return RetrofitUtils.url(getBaseUrl(), getBaseUrlEnd());
    }

    public String getUrl() {
        if (url != null) {
            return RetrofitUtils.url(getUseUrl(), url);
        }
        return getUseUrl();
    }

    public Object getBody() {
        return body;
    }

    public Object getTag() {
        return tag;
    }

    public Map<String, Object> getBodyParam() {
        return bodyParam;
    }

    public List<RetrofitFile> getFileList() {
        return fileList;
    }

    public int getSoapVersion() {
        return soapVersion;
    }

    public boolean isSoapDotNet() {
        return soapDotNet;
    }

    public String getSoapNameSpace() {
        return soapNameSpace;
    }

    public String getHttpMethod() {
        return httpMethod;
    }

    public Type getGenericReturnType() {
        return genericReturnType;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public Map<String, String> getSoapHeaders() {
        return soapHeaders;
    }

    public boolean isAllowUnsafeNonAsciiValues() {
        return allowUnsafeNonAsciiValues;
    }

    public String getContentType() {
        return contentType;
    }

    public Map<String, Object> getUrlParam() {
        return urlParam;
    }

    public boolean isHasBody() {
        return hasBody;
    }

    public boolean isFormEncoded() {
        return isFormEncoded;
    }

    public boolean isMultipart() {
        return isMultipart;
    }

    public RetrofitInterceptor.RequestInterceptor getRequestInterceptor() {
        return requestInterceptor;
    }

    public RetrofitInterceptor.ResponseInterceptor getResponseInterceptor() {
        return responseInterceptor;
    }

    public RetrofitInterceptor.ExceptionInterceptor getExceptionInterceptor() {
        return exceptionInterceptor;
    }

    public static RetrofitRequest parseAnnotations(Retrofit retrofit, RetrofitRequestFactory requestFactory, Object[] args) {
        return new RetrofitRequest(retrofit, requestFactory, args);
    }

}
